/*
 * Copyright contributors to Hyperledger Besu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
package org.hyperledger.besu.evmtool.benchmarks;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.fluent.EvmSpec;
import org.hyperledger.besu.evm.precompile.AbstractBLS12PrecompiledContract;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;

import java.io.PrintStream;
import java.util.LinkedHashMap;
import java.util.SequencedMap;

import org.apache.tuweni.bytes.Bytes;

/** Benchmark BLS12-381 G1 and G2 MSM */
public class BLS12Benchmark extends BenchmarkExecutor {

  /**
   * The constructor. Use default math based warmup and interations.
   *
   * @param output where to write the stats.
   * @param benchmarkConfig benchmark configurations.
   */
  public BLS12Benchmark(final PrintStream output, final BenchmarkConfig benchmarkConfig) {
    super(MATH_WARMUP, MATH_ITERATIONS, output, benchmarkConfig);
  }

  static final String[] scalars = {
    "4e826175762bd086135d18ae935fb085ab3e12b0f5aa4ea3aac99a1c41afae34",
    "7257faefdb84241d947a02c5d19daee65333d6277dfe7212849528eb7812bede",
    "d291f31a5a96f170cc6dc8144562f8c7dbe67afe79c2a2ec53222bc129cbeba4",
    "b99e32c244f2de2fc6b462a55584229818c5c4cdfd2c74454d7d85e58d8a4809",
    "cdb41b97d135aff1d848c3ee8885073a972cbdb92ab5f1dc79e89840ef51f6a3",
    "d4c909fae1c3b026ebcdb4a1885c1f5d8b6cb4aaa9cf8712e8a3add53da55bf0",
    "4dd3dd8562816ac0bd72081d2dea42d27078a5618ff525bef4fd2628a6fb4326",
    "0c68f33b013b0bc960b4e905e75e225bf27e468692d0f271e7e30af23b905393",
    "2c2dd13c6858693241613d34d45cfcf05c5f71fcb5b34483d8ef3133e5af6304",
    "0b4fca47643819aeea5fa85035ffa735c0945fbe6e1170f9639ca478b45a41fd",
    "1e76ab4951f522acc99225ef30b9b4936d27134e76d86222e8b916c9cde4bc78",
    "36b4741673e3f433bf460632c2a89b279e8032d7b236c402f4720b361c865a04",
    "e40cded572e8ad87da276d41d08edafe10576b526776b8e71c6d80bdf6239932",
    "25ea3392dff756934628f586ada2225f5af0e03078d704cde4da460875698e6b",
    "450648e218031d8307ae71a369d95a86ebe14db8f5d394697633a379be496976",
    "f03b5f08231c44cedcea848dc18a42bef0895ba4696e8ec7ecaa0615a5158883",
    "9fa8482dda8cc2f20cd9b4dc63f72be23a7652e7e5fe1436b90b477adb735ed1",
    "0978dda7cb30dd643e472b0a3f8196fc51fad22d30f0f01d7cb570d85d7b353b",
    "387b7f3f892cc754b5dc6c724d89b791934f6914778b5c84a6892abe6b999ab1",
    "1d2b5094b14b26c9ed3100222f19bbbb289f2638c29f5fbbafd68574873d4287",
    "cd7aabd84ffd41b589dec5d4af4b17681218e1fa16a3e9855385d35b18dfd2b2",
    "d3c6c9bb36e9d5647eadd40ac68b57e0fa17352f558f270b8f7724f6dd3f19d4",
    "7d7f485c07f94d37c80e6710515863b780883e2beee772bc7d7c1cc0f10ed245",
    "8d7bd0d7a9ff1fc481fc6b9a6d1c58d6bf01d7017f7a3bd1b826d38076d1c6fd",
    "f939c5d735bef50e7d22408012d3bb664179d098a42fa2f2dfe2bdb8f9b6c074",
    "b02686dd55be9fc6a791cac72a2c32b5e6f86c0f5b92b52f2efc72ac2043837d",
    "11073c2c13655c6802ae8918403d17106d630b7519bc61dc6e592bca5f7392c8",
    "fb8130bbf0067026d67d44e464b568db99e0dc02dc48fe8a4753d806cd647d3f",
    "a558312bdbefc905932e51cb05eab0cd546a8f9a41a135746eac247840ca434e",
    "9b5026e422f16837ca568490bd4ebba629391319b9b076d7c644989991a00c94",
    "c480e504a8ca9556770dd3b9cd8d515f505098c0450679c158ed54f75d9224c0",
    "8b450d2be25e0f596ef0c1a4fa06fbc044f087704469f499aa8967ce8844f080",
  };

  static final String[] g1PointPairs = {
    "0000000000000000000000000000000009f5bf486941d9a9f8c742fa43ee279d75419d4c11d1fbaed1dc19c624e168dcfe50ce4673d7ca6d42051dc7b799d7b3000000000000000000000000000000000aa47f7618e3dbe09730b9d378ac113dd841f7e42dfb390ff486e2820345208e2d7433244eedb233bcb807c08c55919e",
    "000000000000000000000000000000000786d2c808ffaa25cc78e484da52b01698ad8eb55846961d2b62fd578432f3466da7e22cc34298fec4e34e33b88243b300000000000000000000000000000000015e8b79f94e318336bc50f0cdc4c9bde81052ffd0fd48c5b915be878a1a1b2f3a71d7587fd9892a44c9ec71fac5bb80",
    "0000000000000000000000000000000016206b9006c026c95c2879f2b950a074b2660333962e21d06d3cf1a9d6ff33921349f286a9002b515b384104a32076de0000000000000000000000000000000009b72f249f9037ca7cec181df2f5798d0a8253d86dd61ca6e416cd1652bd4c400a5689e6d29783fa1a8578700470146d",
    "00000000000000000000000000000000093f21aaaaf2044cdf9a80ca3afa75db4e32aa2870fb6b9dbb22493956d6e01a7f566d567b67307b1ca91355669b28d100000000000000000000000000000000083b0a9758f5b562b930f24456e56845a87352a9b28367df59f46b570af1b8b3f2a4d4a7e9d272faf2fdb53d5077cf51",
    "0000000000000000000000000000000003cc0abeff05a8d78ee0e94d8cf71d6d0a5889968b99e5b9c6a3d283d7fcf44caf8c11619c75020bf9dc8e8fb451407d0000000000000000000000000000000005171356814d04c944564fbe478f1c953c96d5b8b269813d0a31272346c078956103eb2808ae2c83528066a9e54736fd",
    "000000000000000000000000000000000437b80cfb19bc01e0050bb3def6da7dcfc7b26c4eb35b2f922685062bfac10d78b02d86ab45025286bb9f3293c2560f000000000000000000000000000000001934da79acc0e74284af492d5fb1f942ac5ff8660f18769f4f241ec724df952c9286eee55683b4c495f1cb4c3e1fbbf4",
    "0000000000000000000000000000000006310c85629fe02d094c224f83dbfebd9cb950ccb28832000771663bb93cf4cb8ad8016f0fc4ee42f8584ad8ce00498a0000000000000000000000000000000014264f7c2fe86174729843b3db54cdb76b5a892fc73a5e67083b937448634e516a93e170934c1b8a30c71a8405735bb3",
    "000000000000000000000000000000000b6539f785b36fd3dc041676bd37c77033c26e3881b4b47fbd093eb28c7ce9ecef7c9b588850e08ec06793d0e0034d95000000000000000000000000000000000401571cd8ef0289d239bf7b0115708e2ba04a577548c38a5b283cd3bf945185e2f7ba744ba345e60a61b9405865a67a",
    "000000000000000000000000000000001861eb880875a3f7bb7a45eb2dd32adffb68abf1682a5268a68fd9691db119c72f7f21cb98884619ec09f4f9a9189816000000000000000000000000000000000233a0e8c1f4c7dc3e4672f7a6a1e226bb07f445790f5d0c5b1437a3030e4b4e95645c9d0aae16e570d79af0830b8ada",
    "000000000000000000000000000000000f99c56935dea38c1691645d3ab576a762b5559c31c46edbc8c70b74c3b40f79c84c4623cc72206732a620beec0ed10d000000000000000000000000000000000786714ffa00436d9e53f898e98a5fd3bc799dfe0eac8f7ab4204b2c9b464329aa14bc58aa23ab1606113b8a90a98b81",
    "00000000000000000000000000000000005e8658e3105fe051190127fba5db7d2ec47655bed72acc1c4a9b985b1330932b6e339d76d9f56b2b8d6e8b8cba1f420000000000000000000000000000000019e18081a769839b3849222e2f9bef86f50f398409d776e7e5f462bef75e8769a7257139826ae4dab7be8a344e43eb35",
    "0000000000000000000000000000000005cdf9c9f5091d495d7c8707505c9051fd6bc2e01899bdb24d8f55e97e0c034b2ea2173c73250acf3814a3751659b653000000000000000000000000000000000adbeed0c8abdd5650502e96a14ec1b0af697d27f1de92e82a4d70dd763a7c83df1e1483a73155a7362ab6e830cb5b60",
    "0000000000000000000000000000000006aa3ff84449d8326edc0971e18dd77d06ef2f7214c8849dc9db9e9541f2788e84f1713daa2fd014308321930f474493000000000000000000000000000000000f39da6466995da0227cef277bb50692373896bca7b0c6dad3fa6241e367186fce75cfe67337e59660adea207cf21578",
    "0000000000000000000000000000000011079caf8ecad1b7fc8a5e52fa02e2cc54fdeff788ce74d94de474e964736da7bbd48fe103908fdfaf21e618cd8bd570000000000000000000000000000000001391f3f5ac9d63bc769e3462323a25349fb879849966a14c28d7ea4c43656dec785e9c10e600fb2c77960185a25a5a30",
    "00000000000000000000000000000000030ada1568c82dbe97fc8b7f3f0119014513ea86a109f76d4e0fab865515c1a2a2f062da5d2fec52585fcbc61b62822700000000000000000000000000000000141e65d12ff426e2a6b665f7860e8dae8d1de1e4e3a3a062032a555d79e820bbfd727cf769980bde73dd181db7b4ef4b",
    "000000000000000000000000000000000e17d2ed1881b7513d2323e606c6551036c86f1c455657e8c7d56bd95ab906d9b2cb56a244ddbe59e7552d1eebb1e19400000000000000000000000000000000176bfc0dd0953a54f5c3c162a7b5d30375cfda78da80975757cf9496b9aa015263efb035a0361c794c89478896cd1e82",
    "000000000000000000000000000000001560b598256b713e21cb49b0e16849456d555788a93d1bb778ad7f8f4b090cf0aa115a5f0535eac2276fd1d81d10db44000000000000000000000000000000000d6d0b42990da37fd54801164a148adebcf4ed22874ab64f78f6d323a3bf07ce8470214c4bfb4a0a2e5d979d34f8091f",
    "000000000000000000000000000000000a17df46b5bb50ed8c065aab3b551a1a174d85758169a57f952c08a6878466efc0faad3439b341f9e863e360fd2450f7000000000000000000000000000000000e20917637b3f270025909ecdc1946aed29389d60af02933b3da348ab6ac5380198c8fc6985547c7438452c7d977ac41",
    "00000000000000000000000000000000139e3c560a50d7fb86e3b59fbac5445f9c0ab0978b3cf1d6d51d5dbfd86b8233c1a0d13a3bc3c2f266d1d938519c801a0000000000000000000000000000000014fd5a3ca318171ef34723ee5cf58b4736105cc69e5c3a10da3fb895e45f1569fc5ede086a5737281280f11ad7d77b1d",
    "0000000000000000000000000000000006419acd10144ced4f53b8a875f6ff40b777af68ecf3e7245243b9c74037fc128ed2c9e6304e629deac852007695b615000000000000000000000000000000001234916bc5701e0b43af04174cf25b780da79f643f5dcb98748b3ee9c5cd9d39e8c026948745970cc1d7e839616ef649",
    "00000000000000000000000000000000105f212197eb701ed73f5c3ef3a6504d10e20ce70de26a76f3f1e5ce444d1a24e2384d63d4dfd3998d6cd938505adaeb0000000000000000000000000000000016e5f4d98bac752563aefee58920392f3db9c24873c42cd7d0ac7f26a412502dafea025fc63a7b45f8ff5f390a76c7e7",
    "0000000000000000000000000000000010e3a266c9fe2ef7bd6da2a11ad73466d398177738a69629a55fdd33ec088600d750f4b270213f091b25f67d7d4687d50000000000000000000000000000000016eabfcc65d89e64317145fd2dfd397841a20c54518ce9133cc38768fe8a12aa937b25fb088a0f92cd9de81b45b1ee24",
    "00000000000000000000000000000000196205afe922e753f3b9907caedf380fc506bae61e12bf48483560c32f7f62d28c94b3a3661cd8e09f6445893f471e60000000000000000000000000000000000385e8e99fec6bec5a6ca1c1b947317a7f98b9d6860228a752cbf909153a5ab045a9fafc3d0d10f4d38e3e29311fb9e3",
    "0000000000000000000000000000000014ca7e56d5209106aed424aa92d8b9a746da0eca913aaf5dbee3cb010fcd7db0a969eb5b8ba56a222d29424db5d2ee43000000000000000000000000000000000df722a8de5dc9333df241f1b8eec12c3c3c34194f065dabe9177c00928279db561ddc648d074975921fd6ca9fe795b2",
    "0000000000000000000000000000000017f9ffb90222613c6e03da79ce610a53c10b218ab1a57e3b8c136ea22360f52965f9b1d349f25ea2e7d71a669c8b12d200000000000000000000000000000000150f4c0c65de339cdf44826213be1c5307fe820c80f44729276af0d5e3f1e8c1b7eedba77ab58f742f9f045493a4f583",
    "000000000000000000000000000000001643c91e1ea8ead940645595352fb680642deba457b2222b415144fe64d0031b8efc4de5d7c42f63c6e64a7be988514200000000000000000000000000000000143b72204f89fa6fcd6f603e370904e532acbe51930495bce552e3eb2081453806a432a18e52874e495b989111b22435",
    "00000000000000000000000000000000165b7fe90a6e39a14a11eb729aae227f35cf9ae240bed66c296e616c7a4912183e985532d5a5e1200cb42a5392b33baa00000000000000000000000000000000056a849e23ffcb32e04a1aa50b3402efe8854173180c8ebca1c55e52a59629e8557c6c8f3914cb03e9088e371ef2f835",
    "00000000000000000000000000000000066f0bc365eb53a05bc9561d32af5d32acc0796f5a76eaa1c8f15f1b0a3ac6f3bc911bca630749dcc64ed2f9c4e25d56000000000000000000000000000000000f9ba6af35d2f116f4341b03caf175bc27f007d5645866dc3b3bee8665d45f204f73e0e25cdcfa339b2946773919e804",
    "00000000000000000000000000000000104673bac88cbacfd38a26aca0a5435407e2086f2c666c89b5769393bfc247a10937ec3441c6c274760b590d2622a9df0000000000000000000000000000000019cb77c56ad20e574cdd0681bfc1131f069f58ad8e3a5e8898cc100a4c59e503a400e095d44bc5cdffb2ec8c07825ece",
    "00000000000000000000000000000000039faa653341ea8e2ddfdf2bdc5de84d8a1a9027abedab3cadf5c1fb69262f0db7ea94ac8bb2abfb132a000d390b58f80000000000000000000000000000000012aadfad64ca2203860ef91a1cb88cbf817be2676ad25c7cd55bc84a6012621a41909fe28325276aa3cad5baf1be6cb0",
    "00000000000000000000000000000000004dba2a3ff8eb3ef159ff2e66c65f51016efb2f755ef41089f84960dca19a62d6677ecc59ad1a7ca3abf4d11944d53d00000000000000000000000000000000002a928c7e135f095226050069ea0b219d42b8865cbae0d3ba9f10aa283dfa7c28f1778adc0225356eb2579379b57263",
    "0000000000000000000000000000000017979ff6656fc8d015b8b5d486ae947000d277ce55a69b19d63f63ab654aaf0892dda72dfbc082bc3bef59f96af872a20000000000000000000000000000000019ac1fe79cb8a3373f7224d4115beaf742cb3bdafd954aad002c2ba24874392f6a0ba5f5b225d3c3c3cf82979254cbe0"
  };

  String[] g2PointPairs = {
    "000000000000000000000000000000000bb1edbc28a9930c190f6f1d49f8964c13c13940242e9d8688717ed57149389453e048e3e43a38ca28fd8a07ac60e5960000000000000000000000000000000016ba918cddac3b49dcf808317f7490e5dd49e6594ee9ee9b584261a1ce43a3882b3e1362863537fe6ca429dc17f28e3c0000000000000000000000000000000017ad94874960ed6d0443ca1b8906f84adec505795684c54e155ee8de878b219bf65ed125f3dbf42e3905fbf985e59764000000000000000000000000000000001782e9b75fea3c4d072bb86858c76cc368a67a1f2597a4724e2c79f7c787b4737c2f642dc32ab10ed66f40ae675b1a6e",
    "00000000000000000000000000000000031c2efcc72f74504a2057906f93bef5d47b2482b1eb6d4442563988798b1385010a64f8e1b38a93e6e06283f4bf43d1000000000000000000000000000000000733cfcab23720f699b4c02de7a211482c84e6eeb62a3d901b557fdfdf484ce27c33f56fdcbd542430d72fd78d2ceab400000000000000000000000000000000152daff8a24165368b963d4f4560856a74be3f0dd3879bf4d75e34eb70c201661921460085ca06188371fc9fbfdd8eaf0000000000000000000000000000000008a6c6a920452e4ff0c8de495b93c9e971af127a5c0d0143fb61d0c981883709c64d837f41842729f8ce926f8634a11a",
    "00000000000000000000000000000000149c85c410022026a7a89b7f52b9b3e3d3f3629ca7aafb0e21cdb9539856990fa7f8bdbeb19915a072c37f1af35d72e00000000000000000000000000000000002776e9edde84ae38e88cc3bac626066ca752d3f1d381b3919e5f3ee1c15b5b513dae00444cce37c732e1a0b6868207c0000000000000000000000000000000004e5b747b2cdd32bdb52e1fba8138f5e44ac98f365aaff35c99399eb115af904c569995d8ed4d87ceda4407e0c5569d90000000000000000000000000000000015f6a5da3f739d2b9365c6031298cd875a6746b3e866e4605f8b82e20e282f3424cd8bd86ff35652ac3d25a3696bb294",
    "00000000000000000000000000000000100f6cc96dcfc630d73141bb8be25ba2256ea81f2d7f55ed0cbe50333715673cc36a8f37a10f3222111afce400bc9ba70000000000000000000000000000000015ad4090a4a27d9939a1f5768dadb247e17cae0f101c5e3b588cfd303e4424a0a937cd02127708af7b1c20eb9405329200000000000000000000000000000000084cc62a4313b2a8d0396d8cbfe0ffa08171062042dfcfd773dd88d83a164c1cc435de4d7e04b36d9146f914e6880efe00000000000000000000000000000000099c27c3a74eb6eab8556fd8861c9a96a7b7032745161fcad09cca9cba13f992d54c3b13e4bce08cba158996ce4dc7e3",
    "0000000000000000000000000000000016437f645c71e932c9c62f6076e25adb6e8e2ba2a124d01762a8fef382730352d7b8d0cebefb51d7912c78532ef4cc000000000000000000000000000000000018568a31a5005deeaa6a0750965f856bae2a5fc3f76b5743ee45852a177ab7fc0eabd9c402e53e2ffd3bec7f600e65a40000000000000000000000000000000000312e67aac16d8433565047121cfed6cf8c968e1d090996342d6c417e778407f62be6b73034f855422904b4f0dce31c00000000000000000000000000000000023bd285eaf6a36e8362b0b647d121ed980aeaf4523f65ab587312ec4eac28612637a39a0f05898bdf711b68bd32be79",
    "00000000000000000000000000000000195e4ef43e2515cc7d19bfd3aa814b9f9e2ed4913f65fa8edf38e66aa64ab98eed6c0b54d6146d9455059a900b325ae9000000000000000000000000000000001158355772c7af7533a7fd22fefcec6855ebe7ba2a0d74e8f549f64dc363ef00495bd1f363686a8518a118e4a103674f000000000000000000000000000000001670781d5d8c7a080e2dc286347a7036ef8cea3d4a865996e5232c2a6e92b23eb74020c1fb6171bd0045d04e4fa07bce000000000000000000000000000000000eb69584271e1671710581dbb381aa40fad35b28e63578c5fdb1b408d13d5f77654d1aa99c9856ac150ff4824ee7aba7",
    "000000000000000000000000000000000e86e03117fb5327c9deac44c0053dcb9956b1d0c6e948a43aef6c07f5ff8c2e3bc3cf8e6e06fa54923ecb8ede6d9ac80000000000000000000000000000000016095c62b00a2297aff748c7c7ae2e48c1e92c8509d05e5cd91af473442f3db56289d5f0078a8af722bede285b244c9a000000000000000000000000000000000399422a0d7d1618f5ad1cdee685d5c91cdb257b4743e7c8504328df81e6a345f073d46477ef2ed27b85f4a87033b5e80000000000000000000000000000000002c8853c746b06ac0bb83ea3444ccd2beb1595e42047a09e9321375ca51cdfd0eabe5c7d4c7e603df44c404af5b84755",
    "000000000000000000000000000000000e6d721b7ceb4c026c387fba083484264cdb87c979ab45aceb0c800ef0af7b67ca495b4e8e929077f6b2d70552843551000000000000000000000000000000000076523e8c6900242bfda291399fd6a0900cb0b7745d7c150a27b692ddf047a6bc2b5bd20aefcb38a9550d45beef2ebb0000000000000000000000000000000004eb54c19ed6a4ba9be94d17fa361dd677c5e9c0ac27f15f3da745cc9245ca5114570a8a44570d643ca6fec24c5a8e9a0000000000000000000000000000000001fbd43e2c73b106c9e59ba823a264d5926addf6988e2cc97847bad292359cf77702597c9df33b0251f328da8f209cc0",
    "000000000000000000000000000000001557006e7c861c31d73400a9eda26c9bdf064756f557688d65fc6d5655053457db932c4d3db10407a4ae592047ff842d0000000000000000000000000000000019cca0f57689d18ce2161e0930274f6cdf3f6a71f10070e7257a0698e5a9b5d384f52623bbbbdb540d3e9a64c10e921b000000000000000000000000000000000a61fb9a3484336cf570943a7bf1edddd02b73d736cd11fd6032c2fab8194781126d62f4bf23f5dd2c1bbb71659f2b500000000000000000000000000000000017b2533e34dcc2d571b34068b6d3195d15436efa3848d66b108060b5d15e5f285fc22a4aa323a2e3813c82f78dd4cacb",
    "0000000000000000000000000000000014a079a52523718313ba0ea828e16f1f7fc053ffd40359e583672b81253ba4e0ce2ee25ff8682bff102780a81f1f5eea00000000000000000000000000000000127944d2093486199de71b90ef794c172eeb1096d0f1690d7338424d96acdfbaac3733c937359e48204860d744778de6000000000000000000000000000000000735d8a013b801883de71f0b942cb138c0ad8a7372412c5c364a1f952664ad3589621021a23a0fe1c961f428d527b53f0000000000000000000000000000000015536982fda409e63704a7b3cf623bfca1bdaf462e906085acded40f299d37ac4614622781310aa1afd82066fdb7beb0",
    "000000000000000000000000000000000d0f91fedd8bf219e9abec47875720b58cf95b022bf4eee856df2a0e6fb07504d7ebc9685fe5a95318004833b7f616800000000000000000000000000000000014c82ce968273fc7873cfa4e41ef9933ae3608d2aeb4a278243338022d870b63c65d0f3ee5b434a96a366099f78aa2fb00000000000000000000000000000000198ae019725ab641f7b8b3e24f69d72132a3c90f45708b27b7346ac8949f7d7bb3ae986e7e2c718b58bd79e99143a8ef00000000000000000000000000000000056374901ba836eff22b7c24587e62831e3a088b46f921107598a3f94509b13f6776250f6d011e14d1566cb3e641f22b",
    "000000000000000000000000000000000b469b60961ff21ba768adb10a2a64e4782a3ac7e703a7637259a51781308ff6d2837c9fd28be2975ba4211a60a0d88e000000000000000000000000000000000dbe8ca42b9596dd0657d415eb6321c7d32c0e475d97cf25672bb97f3ec375d90d57ae078d3777f279eee381bd66e6b50000000000000000000000000000000007b31b123718b7f235fcee6a78f7a130d4f5d03c22f4869438ff0fb3806c7aecbdce535db9c8b61bf48b3c550fc9404c0000000000000000000000000000000002d982b4bf793d6da748b9a6adee65a7fa093e4175a53c763f2e23dd1fff051e0488fe987887dbd45b194353513898a1",
    "0000000000000000000000000000000010b07b05683f03aa5c03681cb0726f72d43e2653d0e1c9538811f6b858755ff9b680f146c573c21a953c753c1519e10f0000000000000000000000000000000018df2ce2418f296e147059ac69b26834a07595ef62d94506b0b7b7b58457e740089cdb6fa7a52e945b6ce28133392779000000000000000000000000000000000aba7561bd4db53d4f5f1f0dcb943ac841604f786712b257dda889962f2e85c55a97410d13bb115409b014927f1e19d70000000000000000000000000000000014f72efe6f6c259c8adecee7027b1707cd141d1507dd266b7e2e7bb287a5f0b71f8decaa1697adee1bf51cf1c4558181",
    "000000000000000000000000000000000e0faba97d411f80e2e3b9a6d39d7f8501f2043b3eb8649128f21c530d976ff865b5ff3f5f691a0437b611427de5ec4e000000000000000000000000000000000d65fc0c62ed95528f08997c3b9ec5bbd81cd8bc66d2a9d3090719f851a144165b54ab6e7b8a619a1286fefc856fdd4c0000000000000000000000000000000007422cfcdcb04bf8863d005dd88856ff639e2b94985c0804fc20a939ad70c263d91a45706df9d9c6d7a5b18f801fcafb0000000000000000000000000000000017ca5d23734591abc516172fff615b87e219b478b8d8e64e316ca71a2c64c66f9a526cf7e4a4a63873ca94e63d82cd29",
    "000000000000000000000000000000000bd718cd80fe3a576c196b42c5ed99311d32cfed42d66d3a084c719215359d0654dc18bd56a23db6a7fadf9fb08187b10000000000000000000000000000000003b20b43a55669e51f34aac5f1c9c93a8b9f93c3b16ccdb11026fa2fb637ade15bd96b256703454a1c50a8856764f7d30000000000000000000000000000000000545144715836136b237cd5b1355946208c60d2ab03e0db14ed6d0098d14c985d198a65556d71d87a9d5593093259a90000000000000000000000000000000012d88272dc634dd86c47edf10c84c5482063bc9bc194f9cfce16bb75b54338cb3e68bd63ade2e65013513fc827700b6e",
    "0000000000000000000000000000000014862df8fb650ae94f6f642b9b494f89dd7adf12e41ae73775ec65e53239eae2f9025340bee6e673071275f215779e160000000000000000000000000000000003170cd693576ec1af09e1b5ef5197a23c83de1d123bf8dd61811a5cb86e251c907154c1e97783ef52812caefb3bb58b000000000000000000000000000000001002d75b4532d5cb5b8d86de02516f80b901290e1143ea098ffd8a1e1a8332f7dc716db3ef22e639e3d01592599abd82000000000000000000000000000000001666c5981bf1de72590e79e0563421e851d404825aeb4b02c12dff618945250affeb42138a6e383b2804abcd586cdd3f",
    "0000000000000000000000000000000013be6288dc1ec813dcb80a244c2701cbe65af0185fc5a9fe479979f97ed25805fa6a5e0f9cd1644df8d03288daa24475000000000000000000000000000000001822963965705a42d91ff958bb6a23162b560d3dfbf43b165bfc679dfd765093497e7695e3201e89867b414782e47cd60000000000000000000000000000000019b7376b974d00abcf4a325eb93721e89005ae5b701fa14c4ee063929c6f4e37ffdc3612ec0d5287c4b19c3cb800c1f80000000000000000000000000000000018c899e91c3bd7d52ece713413e2e733be459c53d6e08b62c34140115d9ebf112ce7b1e4969f75408ac50a8f1b057064",
    "000000000000000000000000000000000cac21c55ff3d3f836c684c9bd87050101ecbfbf947c1e9aabdd5b8c65643b38034372c5c29a9e31e6bddbb92759dabb00000000000000000000000000000000003da40ca1b9ff45aef983a8fac73051c5ffa5061277354391c08d9a8230eea8190286111a5798825af3d12b1d672b9d000000000000000000000000000000000cdeebb1738c02ff85d19664d1b020f4f1665f507e918584fd9a1d0547401400386426cf40079df25ef30e254d216350000000000000000000000000000000001339d03d31f99756141568b165ec6c6b19247e87c75e58a2cea15fc88f7d2be371e410e0b0eb0b1a12deab13133d13ad",
    "0000000000000000000000000000000003b746c6ff13a38d21a02fa1411fd4afebe3b7feaa19d73514ae9db9d1d71209ebd3a882f9bb3d2e281398bb83a66bc5000000000000000000000000000000000d9b460577687f06263d7cb76c222b15b8935790e48b07dd567571e409495da5db324fb107b9a136f17f58660ffaf9530000000000000000000000000000000018c0a41dcb3b48eef7596342d56ca471dd2f34a1fcf44f997b2c6614b45cffc7355d71270b517d873a38a520d32c0b7100000000000000000000000000000000118d21253a52bf38a59303f3eb2c747ff951e6853fced9ecb5e4ebd969d741612d43e552067c001bd3d8630f077907b5",
    "00000000000000000000000000000000009c9b846d3b8262703bcd56a584a423f2d6ea0009a242f45d60ac04146206a1fd0bf2d709cebb5276b32a34d08937af0000000000000000000000000000000014485fa2c535058ded72048ae7e3194434f6beabf94bc7048d23949a69f541c3fbfdb4270bf05e128a1d6648c9a59534000000000000000000000000000000000714427d464c715ca5720174ad15540598272fc4b9a5a0657106a4e9abe130935ebf6bce5749df1880000f06bd1922b8000000000000000000000000000000000e8916b52c09791dffb80f221d8868c2af09ace7304cd04de1c7c1a3d593d2be349c106b908e37fba49de0e72688a16d",
    "00000000000000000000000000000000008ec6c01d64c02bd587df809ef7d363b415f736080bc76c6440c4fc2a32830e802907ba906c49661964927641866f22000000000000000000000000000000000e8a4da56e0d8f93b3dc6a4f0c8279208758423bfd592d8f4e911f75cf3452ef38ca771b496e26be08314e686a7524e200000000000000000000000000000000031aa3a4b68776131eb25ce44ee3e5d6703207731a5c1e4744a8af4f1e22d272dfb32ab1fa37a93f3fcb3c8cfa63626c0000000000000000000000000000000008270d9d15296d653b3e10ab4147f0a467d0f862629f9d248aefd1ad7ac318cfdcc05319da14cbe9fa475887dbef437b",
    "000000000000000000000000000000000d4cf12bc66952beebf74f7720bcac085313954003e9d0b5be9bef06765e499c0f085966a42514dd42249735e1232ca8000000000000000000000000000000000b94b3dcd69b0024624d46bd3caf65a72f497a5317cfa1511c5b11b4b71d2927cd7ad08b8c9e60b81291cdf12b2e2b610000000000000000000000000000000012ae5a383c683e41ece77ecb31a33896efd6d0243b1b5d883e6d7a54f1d5a3dfcbd2257a2c5136e3e50d229854043b4600000000000000000000000000000000069dd28d9abbfe62498f362e1eadbbf92fa7cc8cc82e6c4cfaef68941e3aae3dbe62fc2105bcedb378165d50a64cbd89",
    "0000000000000000000000000000000009c798c8f428a12bd81c0b98efe660c4249b2cd2fbbdefaadca483e23c7e7b0dd8a9b2c955dfb8990ba066a3252b5c1200000000000000000000000000000000039247ffd499e097ce042b0e249c6650c366c9a790f8d246271954992aa3d209b7c23962132f1f37b8ba05142312d4c70000000000000000000000000000000010d3e9a11526543ac2bea261a897a248548c4ccca19d63ef4b76d3ee323c9c68f251f01b1ed61af4cdbb1835e7afafc40000000000000000000000000000000002b778080e00200bf874dc37d40f6fa9bc111f066373a3dfde706dbb15c897b1fcac3b4bd5eff354330869f30be74296",
    "0000000000000000000000000000000002353771bf8f24b6340365cd7c5fa34e1af4a6d485c6f0d2db82d5f193e649e92d952556b6ea4daf095ac0a9e4e759570000000000000000000000000000000013d62324d07334f3a5b1bf9eb09a0eed954839e43a93599852abea9b39be0d08a82364688067e1689d4457a15fc33d6c0000000000000000000000000000000015f2b988a767cd395d5d3523b93783a1fe615d89eb5b2184a25af1cb4d2b23a40756552c4f5e6a9e4cd09d6bb881791d000000000000000000000000000000000c23f17079a62bf4b73af2b7b4d39c539ab1034b113b89e56e5adf2d3c7d78e5ef1da1fd59878535b9ae56b6928cc22f",
    "0000000000000000000000000000000011667822e52fb4ab060f818f9c186cf5014e7abf62ad1376bbd560630fb8ab74c6cf32dc34c258d2472f5469c1d08a760000000000000000000000000000000006520d658fed38850a9d53e40054b717c837d43ce0c7ec26d869f726e39d0f0478f1483ed50555b3277f4db14b9d707300000000000000000000000000000000147429837f309e14de5345c5cdf0b738b85159bab006cfb11d55becc4f99c45f49cf4a4dbd322ac78ef6b0903e186f080000000000000000000000000000000009d29a5195dc5825328bd84e2e01865fcb71b2da240d715032c362d68a3e22009bcf084ec6865134a0435820ac68a69b",
    "000000000000000000000000000000001725a9af0c2665b1dbf421f8c219b713e7cf3605b6c263cfa514345c0b3c089efabf04c99bce50d66e76661b1fe197a1000000000000000000000000000000001789a23499b823b093a65bdf31a11c242c95c3dc20580e60724403dd4e26581a73dd14d39b0822241530b98c3bd780a8000000000000000000000000000000000def0588cadc12088d34101bbe503f4dcfe7e1ffbd1b73e8c4366634414f0e92d7c06bc1b63944bc389d9fa8091722d100000000000000000000000000000000121db986bbd7bed4ca3ce10a57b3870e06d3dd5aaef06275e8c9f646779b492a8b2710a4a80201c193f3a7bddb30fd3d",
    "0000000000000000000000000000000011e5eef691643dedb64737ec9b7789b4dd882bbd0f8417a6d2d2a3ba3b4f77706883edaed7cceab0b763a0f5a1aab58700000000000000000000000000000000153052c193256204bdc57137b8e57434a051f298fa8865d4cefe79b99c19d536fa1a98a15575920df4e5def869a808f0000000000000000000000000000000000ca8c19e3b556bb24d21d9a3c86b4a22e9d75da7979e53cf60ccab3b10ee428697c468578fa5a091f996fea8b770b8730000000000000000000000000000000005c8a385229f99de9bfdfc72333acfdb1184ebf8c423ef7ff56f765c59dadac6ce879d1a3ebaf01801d525bdf001df53",
    "000000000000000000000000000000001244954d9e9a61f1152d6d01f2fbe739bb15a087162560e7aeb075dc2c807883b967aa00ad9e859e9a729872ba5f4ea100000000000000000000000000000000155e743d267f2b81b0b8f632a077dbf046dd9329f7a47963828e3e4ff9a5d2ec7e6f556374ee633a0db8839b74b9f28a0000000000000000000000000000000001b0fb50e9dfb7045df383629b697f0d21cbe2ac5f20a45d8f3a427a40eb2909910cd70fa95f9f35ac2704b3a2d73f870000000000000000000000000000000015340b22b90ba30ee0266e1ce7a68be54b35244b9bf7ce83be16d5f7ecad9ec14357a2d63df7c0555c1e0eaa977fa0a0",
    "00000000000000000000000000000000051b3961911aecbd714268edbc881c7461025d999c4e23c12994d676b853f2d02932f26733a4bdf306caa155a915a01a0000000000000000000000000000000015749ff11a27b093f24988c9578460acaffc376b2b7027091174e073ada104ddd56152cefbed70485b59fce651cb0b5200000000000000000000000000000000184cf9f1c1ffe553283c6b30e16c4f6ca2db7a23ae675ffef7d2b0f38c1f491dd0b5f2cbcd2c09f95ae3d9f5977aa7c5000000000000000000000000000000001002d00af1ad50c4cccadc59316dd9c246cb1ad31253d430a5dc4ab9b9a90dc9a5377345badcd367b31b9727a3fb368a",
    "00000000000000000000000000000000132b08fe8d911ede6727cc3a519310527ebafb55cb616637f44187b1bae5853773d4b5bca7f58bed803a086d47a9388e0000000000000000000000000000000003be761bd2a8b89a0802c20b4dfffedd4072d699bdd7db97c17f887b5a93c0cfac9c8e57f69649879c59b060e93fe4570000000000000000000000000000000004baa66dde1c1f6500680a955a313fe79172215948989b1daf4f0859d340eef5d70328b9f94c5e5d43d86a9902b55e81000000000000000000000000000000000ce5defbb703c6510e737114194429659d53a9f4011818b5bf35ffbbb281db85f7936f84b40d5a844e2e668a26a2a0d0",
    "0000000000000000000000000000000015c253e204c58e012dd3e9f232096d93588d8471e1ad461067c3ed2599d7fd77c8feb23e6f8a18bdb5777f6640b0b3570000000000000000000000000000000010b5b066f7cd958318e56c181b6777e4acdf3e50466d0a8ea3973164f0c57069a4310705112414ba3f8acef50adfe1850000000000000000000000000000000009abf68d5b5171543116c24102869c785d11344518b91c4d40d07d85d2d437fdaa5f693513c436aa92caa4317de29471000000000000000000000000000000000ee58454ba9d19e308791fac39f48a1f6569e1a842184177906e61cfe902d90c6b79ada57298ae1c57cff09c43a6921b",
    "000000000000000000000000000000000a2ee22112a95fae9392643ecac169b730198e8917c86297c88cc57581b8b563216f38e27df12e4b76d82cba96a41fc70000000000000000000000000000000003bb647b0edb1d2f058c7942c14f6054317f2e1c280e56dad85a789d302de382049c913837e129957c3b2959f3723957000000000000000000000000000000000817676f2e030a451c12e9241a6ed788f0aae24a3fb9cad323169c7a956bc450cae6ce717306922090493183ef5d447900000000000000000000000000000000091db623c0815f2b9848e1d292203f6adda8ba1b6c6a7bd6bc414e53dd95f3033fd93782a95688de7a8888cd04cd02da",
  };

  @Override
  public void runBenchmark(final Boolean attemptNative, final String fork) {
    EvmSpecVersion forkVersion = EvmSpecVersion.fromName(fork);

    if (!AbstractBLS12PrecompiledContract.isAvailable()) {
      output.printf(
          "BLS12-381 not available on this platform %s %s %s\n",
          System.getProperty("os.name"),
          System.getProperty("os.version"),
          System.getProperty("os.arch"));
      return;
    }

    if (attemptNative != null && !attemptNative) {
      output.println("Java is unsupported, falling back to Native");
    }
    output.println("Native BLS12");

    benchmarkG1Add(forkVersion);
    benchmarkG1MultiExp32Pairs(forkVersion);
    benchmarkMapFpToG1(forkVersion);
    benchmarkG2Add(forkVersion);
    benchmarkG2MultiExp32Pairs(forkVersion);
    benchmarkMapFp2ToG2(forkVersion);
    benchmarkBlsPairing(forkVersion);
  }

  private void benchmarkG1Add(final EvmSpecVersion forkVersion) {
    final SequencedMap<String, Bytes> testCases = new LinkedHashMap<>();
    for (int i = 0; i < g1PointPairs.length - 1; i++) {
      testCases.put("G1 Add " + i, Bytes.fromHexString(g1PointPairs[i] + g1PointPairs[i + 1]));
    }

    PrecompiledContract g1addContract =
        EvmSpec.evmSpec(forkVersion).getPrecompileContractRegistry().get(Address.BLS12_G1ADD);

    precompile(testCases, g1addContract, forkVersion);
  }

  private void benchmarkG1MultiExp32Pairs(final EvmSpecVersion forkVersion) {
    final SequencedMap<String, Bytes> testCases = new LinkedHashMap<>();

    // add test cases for 2, 4, 8, 16, and 32 point/scalar pairs
    for (int i = 1; i <= 5; i++) {
      StringBuilder g1msmPairs = new StringBuilder();
      for (int j = 0; j < 1 << i; j++) {
        g1msmPairs.append(g1PointPairs[j]).append(scalars[j]);
      }
      testCases.put("G1 MSM " + (1 << i) + " pairs", Bytes.fromHexString(g1msmPairs.toString()));
    }

    PrecompiledContract g1msmContract =
        EvmSpec.evmSpec(forkVersion).getPrecompileContractRegistry().get(Address.BLS12_G1MULTIEXP);

    precompile(testCases, g1msmContract, forkVersion);
  }

  private void benchmarkMapFpToG1(final EvmSpecVersion forkVersion) {
    final SequencedMap<String, Bytes> testCases = new LinkedHashMap<>();
    for (int i = 0; i < g1PointPairs.length; i++) {
      testCases.put("Map Fp to G1 " + i, Bytes.fromHexString(g1PointPairs[i].substring(0, 128)));
    }

    PrecompiledContract g1MapFpToG1Contract =
        EvmSpec.evmSpec(forkVersion)
            .getPrecompileContractRegistry()
            .get(Address.BLS12_MAP_FP_TO_G1);

    precompile(testCases, g1MapFpToG1Contract, forkVersion);
  }

  private void benchmarkG2Add(final EvmSpecVersion forkVersion) {
    final SequencedMap<String, Bytes> testCases = new LinkedHashMap<>();
    for (int i = 0; i < g2PointPairs.length - 1; i++) {
      testCases.put("G2 Add " + i, Bytes.fromHexString(g2PointPairs[i] + g2PointPairs[i + 1]));
    }

    PrecompiledContract g1addContract =
        EvmSpec.evmSpec(forkVersion).getPrecompileContractRegistry().get(Address.BLS12_G2ADD);

    precompile(testCases, g1addContract, forkVersion);
  }

  private void benchmarkG2MultiExp32Pairs(final EvmSpecVersion forkVersion) {
    final SequencedMap<String, Bytes> testCases = new LinkedHashMap<>();

    // add test cases for 2, 4, 8, 16, and 32 point/scalar pairs
    for (int i = 1; i <= 5; i++) {
      StringBuilder g2msmPairs = new StringBuilder();
      for (int j = 0; j < 1 << i; j++) {
        g2msmPairs.append(g2PointPairs[j]).append(scalars[j]);
      }
      testCases.put("G2 MSM " + (1 << i) + " pairs", Bytes.fromHexString(g2msmPairs.toString()));
    }

    PrecompiledContract g2msmContract =
        EvmSpec.evmSpec(forkVersion).getPrecompileContractRegistry().get(Address.BLS12_G2MULTIEXP);

    precompile(testCases, g2msmContract, forkVersion);
  }

  private void benchmarkMapFp2ToG2(final EvmSpecVersion forkVersion) {
    final SequencedMap<String, Bytes> testCases = new LinkedHashMap<>();
    for (int i = 0; i < g2PointPairs.length; i++) {
      testCases.put("Map Fp2 to G2 " + i, Bytes.fromHexString(g2PointPairs[i].substring(0, 256)));
    }

    PrecompiledContract g1MapFp2ToG2Contract =
        EvmSpec.evmSpec(forkVersion)
            .getPrecompileContractRegistry()
            .get(Address.BLS12_MAP_FP2_TO_G2);

    precompile(testCases, g1MapFp2ToG2Contract, forkVersion);
  }

  private void benchmarkBlsPairing(final EvmSpecVersion forkVersion) {
    final SequencedMap<String, Bytes> testCases = new LinkedHashMap<>();

    // add test cases for 2, 4, 8, 16, and 32 point/scalar pairs
    for (int i = 1; i <= 5; i++) {
      StringBuilder pairs = new StringBuilder();
      for (int j = 0; j < 1 << i; j++) {
        pairs.append(g1PointPairs[j]).append(g2PointPairs[j]);
      }
      testCases.put("BLS Pairing " + (1 << i) + " pairs", Bytes.fromHexString(pairs.toString()));
    }

    PrecompiledContract blsPairingContract =
        EvmSpec.evmSpec(forkVersion).getPrecompileContractRegistry().get(Address.BLS12_PAIRING);

    precompile(testCases, blsPairingContract, forkVersion);
  }

  @Override
  public boolean isPrecompile() {
    return true;
  }
}
